/*******************************************************************************
 * Copyright (c) 2001, 2002 Boris Pruessmann and others. All rights reserved.
 * This program and the accompanying materials are made available under the
 * terms of the Common Public License v0.5 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/cpl-v05.html
 * 
 * Contributors: Boris Pruessmann - Initial implementation.
 ******************************************************************************/
package net.sourceforge.perforce.ui.internal;

import net.sourceforge.perforce.core.api.ILogEntry;
import net.sourceforge.perforce.core.resources.RemoteResource;
import net.sourceforge.perforce.ui.internal.views.HistoryLabelProvider;
import net.sourceforge.perforce.ui.internal.views.RevisionsTableCreator;

import org.eclipse.compare.CompareConfiguration;
import org.eclipse.compare.CompareEditorInput;
import org.eclipse.compare.ITypedElement;
import org.eclipse.compare.ResourceNode;
import org.eclipse.compare.structuremergeviewer.DiffContainer;
import org.eclipse.compare.structuremergeviewer.DiffNode;
import org.eclipse.compare.structuremergeviewer.Differencer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Table;

import java.lang.reflect.InvocationTargetException;

/**
 * @version $Revision: 488 $
 * @author <a href="mailto:bpruessmann@users.sourceforge.net">Boris Pr??mann</a>
 */
public class PerforceCompareRevisionsInput extends CompareEditorInput {
  // ---------------------------------------------------------------------------
  // Private Variables

  /** Stores the resource. */
  private IFile resource;
  /** Stores the log entries. */
  private ILogEntry[] logEntries;
  /** Stores the table viewer. */
  private TableViewer viewer;

  // -------------------------------------------------------------------------
  // Public Constructors

  public PerforceCompareRevisionsInput(IFile resource, ILogEntry[] logEntries) {
    super(new CompareConfiguration());
    this.resource = resource;
    this.logEntries = logEntries;
  }

  //----------------------------------------------------------------------------
  // -- Public Methods

  @Override
  public Viewer createDiffViewer(Composite parent) {
    Table table = RevisionsTableCreator.createTable(parent, null);


    viewer = new TableViewer(table);
    viewer.setContentProvider(new VersionCompareContentProvider());
    viewer.setLabelProvider(new DiffNodeHistoryLabelProvider());

    MenuManager mm = new MenuManager();
    mm.setRemoveAllWhenShown(true);
    mm.addMenuListener(new IMenuListener() {
      public void menuAboutToShow(IMenuManager mm) {
        // mm.add(getContentsAction);
        // mm.add(getRevisionAction);
      }
    });
    table.setMenu(mm.createContextMenu(table));
    viewer.addSelectionChangedListener(new ISelectionChangedListener() {
      public void selectionChanged(SelectionChangedEvent event) {
        ISelection selection = event.getSelection();
        if (!(selection instanceof IStructuredSelection)) {
          // getContentsAction.setEnabled(false);
          // getRevisionAction.setEnabled(false);
          return;
        }
        IStructuredSelection ss = (IStructuredSelection) selection;
        // getContentsAction.setEnabled(ss.size() == 1);
        // getRevisionAction.setEnabled(ss.size() == 1);
      }
    });
    return viewer;
  }

  // ---------------------------------------------------------------------------
  // Protected Methods

  @SuppressWarnings("unused")
  // InvocationTargetException, InterruptedException
  @Override
  protected Object prepareInput(IProgressMonitor monitor) throws InvocationTargetException,
      InterruptedException {
    initLabels();
    DiffNode diffRoot = new DiffNode(Differencer.NO_CHANGE);
    for (int i = 0; i < logEntries.length; i++) {
      ITypedElement left = new ResourceNode(resource);
      ITypedElement right = new ResourceRevisionNode(logEntries[i]);
      diffRoot.add(new VersionCompareDiffNode(left, right));
    }
    return diffRoot;
  }

  //----------------------------------------------------------------------------
  // - Private Methods

  private void initLabels() {
    CompareConfiguration cc = getCompareConfiguration();
    String resourceName = resource.getName();

    setTitle(Policy.bind("P4CompareRevisionsInput.compareResourceAndVersions", //$NON-NLS-1$
        new Object[] {resourceName}));
    cc.setLeftEditable(true);
    cc.setRightEditable(false);

    String leftLabel = Policy.bind("P4CompareRevisionsInput.workspace", //$NON-NLS-1$
        new Object[] {resourceName});
    cc.setLeftLabel(leftLabel);

    String rightLabel = Policy.bind("P4CompareRevisionsInput.repository", //$NON-NLS-1$
        new Object[] {resourceName});
    cc.setRightLabel(rightLabel);
  }

  // ----------------------------------------------------------------------
  // Private Nested Classes

  private static class ResourceRevisionNode extends ResourceEditionNode {
    private ILogEntry entry;

    public ResourceRevisionNode(ILogEntry entry) {
      super(entry.getRemoteFile());
      this.entry = entry;
    }

    public ILogEntry getLogEntry() {
      return entry;
    }

    @Override
    public String getName() {
      RemoteResource edition = getRemoteResource();
      Integer revision = entry.getRevision();

      return super.getName() + '#' + revision;
    }
  }

  private static class VersionCompareDiffNode extends DiffNode {
    public VersionCompareDiffNode(ITypedElement left, ITypedElement right) {
      super(left, right);
    }

    @Override
    public String getName() {
      return getRight().getName();
    }

  }

  private static class VersionCompareContentProvider implements IStructuredContentProvider {
    public void dispose() {
    }

    public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
    }

    public Object[] getElements(Object inputElement) {
      if (inputElement instanceof DiffContainer) {
        return ((DiffContainer) inputElement).getChildren();
      }

      return null;
    }
  }

  private static class DiffNodeHistoryLabelProvider extends HistoryLabelProvider {
    @Override
    public Image getColumnImage(Object element, int columnIndex) {
      if (!(element instanceof DiffNode)) {
        return null;
      }

      ITypedElement right = ((DiffNode) element).getRight();
      if (!(right instanceof ResourceRevisionNode)) {
        return null;
      }

      ILogEntry entry = ((ResourceRevisionNode) right).getLogEntry();
      return super.getColumnImage(entry, columnIndex);
    }

    @Override
    public String getColumnText(Object element, int columnIndex) {
      if (!(element instanceof DiffNode)) {
        return ""; //$NON-NLS-1$
      }

      ITypedElement right = ((DiffNode) element).getRight();
      if (!(right instanceof ResourceRevisionNode)) {
        return ""; //$NON-NLS-1$
      }

      ILogEntry entry = ((ResourceRevisionNode) right).getLogEntry();
      return super.getColumnText(entry, columnIndex);
    }
  }
}
